package com.test.scope;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 实现Scope接口，用于管理Session范围内的Bean实例
 */
public class SessionScope implements Scope{

    // 存储每个会话的Bean实例映射
    private final Map<String, Map<String, Object>> sessionBeanMap = new ConcurrentHashMap<>(16);
    // 存储每个会话的销毁回调映射
    private final Map<String, Map<String, Runnable>> destructionCallbacks = new ConcurrentHashMap<>(16);

    // 用于解析会话ID的解析器，默认返回"default-session"
    private SessionIdResolver sessionIdResolver = () -> "default-session";

    /**
     * 设置会话ID解析器
     * @param sessionIdResolver 会话ID解析器
     */
    public void setSessionIdResolver(SessionIdResolver sessionIdResolver) {
        this.sessionIdResolver = sessionIdResolver;
    }

    /**
     * 获取或创建一个Session范围内的Bean实例
     * @param name Bean名称
     * @param objectFactory Bean对象工厂
     * @return Bean实例
     */
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        // 解析当前会话ID
        String sessionId = sessionIdResolver.resolveSessionId();
        // 获取或创建当前会话的Bean映射
        Map<String, Object> sessionMap = sessionBeanMap.computeIfAbsent(sessionId, k -> new ConcurrentHashMap<>(8));

        Object bean = sessionMap.get(name);
        if (bean == null){
            try{
                // 如果Bean不存在，则通过工厂创建并放入会话映射中
                bean = objectFactory.getObject();
                sessionMap.put(name, bean);
            }catch (Exception e){
                // 如果创建过程中出现异常，则抛出
                throw e;
            }
        }
        return bean;
    }

    /**
     * 从Session中移除指定的Bean实例
     * @param name Bean名称
     * @return 被移除的Bean实例，如果没有则返回null
     */
    @Override
    public Object remove(String name) {
        // 解析当前会话ID
        String sessionId = sessionIdResolver.resolveSessionId();
        Map<String, Object> sessionMap = sessionBeanMap.get(sessionId);
        if (sessionMap != null){
            return sessionMap.remove(name);
        }
        return null;
    }

    /**
     * 注册一个在Session结束时调用的销毁回调
     * @param name Bean名称
     * @param callback 销毁回调
     */
    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        // 解析当前会话ID
        String sessionId = sessionIdResolver.resolveSessionId();
        // 获取或创建当前会话的销毁回调映射
        Map<String, Runnable> callbacks = destructionCallbacks.computeIfAbsent(sessionId, k -> new ConcurrentHashMap<>(8));
        callbacks.put(name, callback);
    }

    /**
     * 获取当前Session的会话ID
     * @return 会话ID
     */
    @Override
    public String getConversationId() {
        return "session-" + sessionIdResolver.resolveSessionId();
    }

    /**
     * 结束一个Session，包括调用销毁回调和移除Bean实例
     * @param sessionId 会话ID
     */
    public void endSession(String sessionId) {
        // 获取并移除指定会话的销毁回调映射
        Map<String, Runnable> callbacks = destructionCallbacks.remove(sessionId);
        if (callbacks != null){
            for (Map.Entry<String, Runnable> entry : callbacks.entrySet()){
                try{
                    // 调用每个销毁回调
                    entry.getValue().run();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        // 移除指定会话的Bean映射
        sessionBeanMap.remove(sessionId);
    }

    /**
     * 会话ID解析器接口，用于获取当前会话的ID
     */
    @FunctionalInterface
    public interface SessionIdResolver {
        String resolveSessionId();
    }
}
